package com.ibeetl.eval;

import java.io.IOException;
import java.io.Reader;
import java.util.Map;
import java.util.Stack;

import org.beetl.core.AntlrProgramBuilder;
import org.beetl.core.Context;
import org.beetl.core.Event;
import org.beetl.core.GroupTemplate;
import org.beetl.core.InferContext;
import org.beetl.core.Listener;
import org.beetl.core.Resource;
import org.beetl.core.engine.DefaultTemplateEngine;
import org.beetl.core.engine.StatementParser;
import org.beetl.core.exception.BeetlException;
import org.beetl.core.statement.ArthExpression;
import org.beetl.core.statement.Expression;
import org.beetl.core.statement.GeneralForStatement;
import org.beetl.core.statement.IGoto;
import org.beetl.core.statement.Program;
import org.beetl.core.statement.Statement;
import org.beetl.core.statement.VarRef;
import org.beetl.core.statement.WhileStatement;

import com.ibeetl.eval.ast.SafeArthExpression;

public class EvalTemplateEngine extends DefaultTemplateEngine
{
    public Program createProgram(Resource resource, Reader reader, Map<Integer, String> textMap, String cr,
                    GroupTemplate gt)
    {
            Program program = super.createProgram(resource, reader, textMap, cr, gt);
            modifyStatemetn(resource,program,gt);
            
            return program;
    }
    
    protected AntlrProgramBuilder getAntlrBuilder(GroupTemplate gt){
    		EvalAntlrProgramBuilder pb = new EvalAntlrProgramBuilder(gt);
		return pb;
	}
    
    private void modifyStatemetn(Resource resource,Program program,GroupTemplate gt){
            Statement[] sts = program.metaData.statements;
            StatementParser parser = new StatementParser(sts, gt, resource.getId());
            parser.addListener(VarRef.class, new ExcelVarRefListener());
            parser.addListener(WhileStatement.class, new RestrictLoopNodeListener());
    			parser.addListener(GeneralForStatement.class, new RestrictLoopNodeListener());
            
    			parser.parse();
    }
    
    class RestrictLoopNodeListener implements Listener
    {

    	@Override
    	public Object onEvent(Event e)
    	{
    		Stack stack = (Stack) e.getEventTaget();
    		Object o = stack.peek();
    		if (o instanceof WhileStatement)
    		{
    			WhileStatement f = (WhileStatement) o;
    			RestrictWhileStatement newWhile = new RestrictWhileStatement(f);
    			return newWhile;
    		}
    		else if (o instanceof GeneralForStatement)
    		{
    			GeneralForStatement gf = (GeneralForStatement) o;
    			RestrictForStatement rf = new RestrictForStatement(gf);
    			return rf;
    		}
    		else
    		{
    			return null;
    		}
    	}

    }
    
   
    /*在线演示的时候用于限制非法使用，控制循环次数*/
  
    class RestrictForStatement extends GeneralForStatement
    {
    	public RestrictForStatement(GeneralForStatement gf)
    	{
    		super(gf.varAssignSeq, gf.expInit, gf.condtion, gf.expUpdate, gf.forPart, gf.elseforPart, gf.token);
    	}

    	public void execute(Context ctx)
    	{
    		if (expInit != null)
    		{
    			for (Expression exp : expInit)
    			{
    				exp.evaluate(ctx);
    			}
    		}
    		if (varAssignSeq != null)
    		{
    			varAssignSeq.execute(ctx);
    		}
    	
    		boolean hasLooped = false;
    		int i = 0;
    		for (; i < 5; i++)
    		{
    			boolean bool = (Boolean) condtion.evaluate(ctx);
    			if (bool)
    			{
    				hasLooped = true;
    				forPart.execute(ctx);
    				switch (ctx.gotoFlag)
    				{
    					case IGoto.NORMAL:
    						break;
    					case IGoto.CONTINUE:
    						ctx.gotoFlag = IGoto.NORMAL;
    						continue;
    					case IGoto.RETURN:
    						return;
    					case IGoto.BREAK:
    						ctx.gotoFlag = IGoto.NORMAL;
    						return;
    				}

    			}
    			else
    			{
    				break;
    			}

    			if (this.expUpdate != null)
    			{
    				for (Expression exp : expUpdate)
    				{
    					exp.evaluate(ctx);
    				}
    			}

    		}

    		if (i >= 5)
    		{
    			try
    			{
    				ctx.byteWriter.writeString("--Too may Data in loop ignore the left Data  for Online Engine--");
    				ctx.byteWriter.flush();
    				
    				
    			}
    			catch (IOException e)
    			{
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}

    	}

    	@Override
    	public void infer(InferContext inferCtx)
    	{
    		super.infer(inferCtx);

    	}

    }

    class RestrictWhileStatement extends WhileStatement
    {
    	public RestrictWhileStatement(WhileStatement w)
    	{
    		super(w.exp, w.whileBody, w.token);
    	}

    	public void execute(Context ctx)
    	{
    		int i = 0;
    		while (i < 5)
    		{
    			Object result = exp.evaluate(ctx);
    			if (result instanceof Boolean)
    			{
    				if ((Boolean) result)
    				{
    					whileBody.execute(ctx);

    				}
    				else
    				{
    					break;
    				}

    			}
    			else
    			{
    				BeetlException be = new BeetlException(BeetlException.BOOLEAN_EXPECTED_ERROR);
    				be.token = exp.token;
    				throw be;
    			}
    			i++;
    		}

    		if (i >= 5)
    		{
    			try
    			{
    				ctx.byteWriter.writeString("--Too may Data in loop ignore the left Data  for Online Engine--");
    				
    			}
    			catch (IOException e)
    			{
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}

    	}

    	@Override
    	public void infer(InferContext inferCtx)
    	{
    		super.infer(inferCtx);

    	}
    }
    
    
}
